package stendcontrol;

import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;

public class FileServer
        implements SaveLoadExp {

    private OutputStream fos, to_cashe_file_os;
    private InputStream fis;
    private String current_directory = "";
    private File cache;
    private Properties prop = new Properties();
    private final String invalid_tokens = "\"*:?/\\<>|";
    private final String separator = File.separator;
    private boolean isSaved = false;
    private JFrame frame;

    public FileServer() {
        setCurrentDirectory((String) Configurator.getConf().
                getProperty(Configurator.FS_SAVE_PATH));
    }

    /**
     * Operation Установка текущей директории
     *
     * @param path - абсолютный путь до текущей директории
     * @return
     */
    public final void setCurrentDirectory(String path) {
        current_directory = path;
        cache = new File(current_directory + separator + "cache.txt");

        if (!cache.exists()) {
            try {
                cache.createNewFile();
            } catch (IOException ex) {
                StendLogger.log(StendLogger.MSG_ERROR, "Creation cache "
                        + "file failed");
            }
        }
    }

    public void chooseCurrentDirectory() {
        JFileChooser jc = new JFileChooser();
        jc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
        if (jc.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
            this.setCurrentDirectory(jc.getSelectedFile().getAbsolutePath());
        }
    }

    /**
     * Функция для сохранения эксперимента
     *
     * @param exp - Передаваемый в функцию эксперимент
     */
    @Override
    public boolean saveExp(Experiment exp) {
        String name = "", path = "";
        boolean isShowed = false;
        try {
            to_cashe_file_os = new FileOutputStream(cache, true);
            if (exp.getExpName() != null) {
                name = convertName(exp.getExpName());
                path = current_directory + separator + name + ".exp";
                File file = new File(path);
                //    System.out.println("Path to file: " + path + file.exists());
                if (!file.exists()) {
                    prop.setProperty(name, path);
                    prop.store(to_cashe_file_os, null);
                    fos = new FileOutputStream(path);
                    fos = new BufferedOutputStream(fos);
                    ExperimentOutputStream eos = new ExperimentOutputStream(fos);
                    eos.writeExp(exp);
                    isSaved = true;
                    fos.flush();
                    fos.close();
                    eos.flush();
                    eos.close();
                    to_cashe_file_os.flush();
                    to_cashe_file_os.close();
                } else {
                    final JFrame frame = new JFrame();
                    final JOptionPane optionPane = new JOptionPane(
                            "Файл " + name + " уже существует"
                            + "\n"
                            + "Заменить его?",
                            JOptionPane.QUESTION_MESSAGE,
                            JOptionPane.YES_NO_OPTION);

                    final JDialog dialog = new JDialog(frame,
                            "Предупреждение!!!",
                            true);
                    dialog.setContentPane(optionPane);
                    dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
                    optionPane.addPropertyChangeListener(
                            new PropertyChangeListener() {
                                @Override
                                public void propertyChange(PropertyChangeEvent e) {
                                    String prop = e.getPropertyName();

                                    if (dialog.isVisible()
                                            && (e.getSource() == optionPane)
                                            && (prop.equals(JOptionPane.VALUE_PROPERTY))) {

                                        dialog.setVisible(false);
                                        dialog.dispose();
                                        frame.dispose();
                                    }
                                }
                            });
                    dialog.pack();
                    dialog.setAlwaysOnTop(true);
                    dialog.setLocationRelativeTo(null);
                    dialog.setVisible(true);
                    int value = ((Integer) optionPane.getValue()).intValue();
                    if (value == 0) {

                        prop.setProperty(name, path);
                        prop.store(to_cashe_file_os, null);
                        fos = new FileOutputStream(path);
                        fos = new BufferedOutputStream(fos);
                        ExperimentOutputStream eos =
                                new ExperimentOutputStream(fos);
                        eos.writeExp(exp);
                        isSaved = true;
                        fos.flush();
                        fos.close();
                        eos.flush();
                        eos.close();
                        to_cashe_file_os.flush();
                        to_cashe_file_os.close();

                        System.out.println("Rewriting selected");
                    } else {
                        isSaved = false;
                        System.out.println("Change name selected");
                    }
                }
            } else {
                StendLogger.log(StendLogger.MSG_ERROR, "Dude, experiment "
                        + "must have a name !");
            }

        } catch (FileNotFoundException ex) {
            Logger.getLogger(FileServer.class.getName()).log(Level.SEVERE,
                    null, ex);
        } catch (IOException ex) {
            Logger.getLogger(FileServer.class.getName()).log(Level.SEVERE,
                    null, ex);
        }
        return isShowed;
    }

    /**
     *
     * @return Имя сервера, хранящего данные
     */
    @Override
    public String getNameSaver() {
        return "Файловая система";
    }

//    /**
//     * Функция, возвращающая имена экпериментов, хранящихся в текущей директории
//     *
//     * @return Массив имен экспериментов
//     */
//    @Override
//    public String[] getNamesExp() {
//        String[] str = null;
//        try {
//            prop.load(new FileInputStream(cache));
//            Set<Object> set = prop.keySet();
//            if (set != null) {
//                str = new String[set.size()];
//                Iterator it = set.iterator();
//                int i = 0;
//                while (it.hasNext()) {
//                    str[i] = (String) it.next();
//                    i++;
//                }
//            } else {
//                StendLogger.log(StendLogger.MSG_ERROR, "cache file is empty");
//            }
//        } catch (FileNotFoundException ex) {
//            Logger.getLogger(FileServer.class.getName())
//                    .log(Level.SEVERE, null, ex);
//        } catch (IOException ex) {
//            Logger.getLogger(FileServer.class.getName())
//                    .log(Level.SEVERE, null, ex);
//        }
//        return str;
//    }
    /**
     * Функция, возвращающая имена файлов, находящиеся в текущей директории
     *
     * @return - Массив имен экспериментов
     */
    @Override
    public String[] getNamesExp() {
        File file = new File(current_directory + separator);
        System.out.println("Path: " + file.getName());
        File[] files = file.listFiles();
        String[] res = new String[files.length];
        for (int i = 0; i < res.length; i++) {
            String s = files[i].getName();
            if (s.substring(s.length() - 3, s.length()).equals("exp")) {
                res[i] = s.substring(0, s.length()-4);
            }
        }
        return res;
    }

    /**
     * Функция для загрузки эксперимента из файла
     *
     * @param name - имя загружаемого экспермента
     * @return - загруженный экперимент
     */
    @Override
    public Experiment loadExp(int n_name) {
        String[] exp_names = getNamesExp();
        String exp_name = exp_names[n_name];
        String path = current_directory + separator + exp_name + ".exp";
        Experiment exp = null;
        try {
            fis = new FileInputStream(path);
            fis = new BufferedInputStream(fis);
            ExperimentInputStream eis = new ExperimentInputStream(fis);
            exp = eis.readExp();
            eis.close();
            fis.close();
        } catch (FileNotFoundException ex) {
            Logger.getLogger(FileServer.class.getName()).log(Level.SEVERE,
                    null, ex);
        } catch (IOException ex) {
            Logger.getLogger(FileServer.class.getName()).log(Level.SEVERE,
                    null, ex);
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(FileServer.class.getName()).log(Level.SEVERE,
                    null, ex);
        }
        return exp;
    }

    /**
     * Функция, исключающая недопустимые символы из названия файла
     *
     * @param exp_name Строка, из которой необходимо исключить недопустимые
     * символы
     * @return Строка, из которой исключены недопустимые символы
     */
    public String convertName(String exp_name) {
        StringTokenizer st = new StringTokenizer(exp_name, invalid_tokens);
        String res = "";
        while (st.hasMoreTokens()) {
            res += st.nextToken();
        }
        return res;
    }

    @Override
    public int getExpCount() {
        int res = 0;
        try {
            if (cache.exists()) {
                prop.load(new FileInputStream(cache));
                res = prop.size();
            } else {
                StendLogger.log(StendLogger.MSG_ERROR, "cache file not found");
            }
        } catch (FileNotFoundException ex) {
            Logger.getLogger(FileServer.class.getName())
                    .log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(FileServer.class.getName())
                    .log(Level.SEVERE, null, ex);
        }
        return res;
    }

    @Override
    public String toString() {
        return getNameSaver();
    }
}
